#ifndef COMMON_SEMAPHORE_H_
#define COMMON_SEMAPHORE_H_

#include <fermat/common/cond.h>
#include <fermat/common/mutex.h>
#include <fermat/common/scoped_lock.h>

namespace fermat {

class Semaphore {
public:
    //! construct semaphore
    explicit Semaphore(size_t init_value = 0)
        : _value(init_value) { }

    //Semaphore(Semaphore&& s) : _value(s._value) { }

    size_t signal() {
        ScopedMutex lock(&_mutex);
        size_t res = ++_value;
        _cond.signal();
        return res;
    }
    
    size_t signal(size_t delta) {
       ScopedMutex lock(&_mutex);
        size_t res = (_value += delta);
        _cond.broadcast();
        return res;
    }
    
    size_t wait() {
        ScopedMutex lock(&_mutex);
        while (_value == 0)
            _cond.wait(&_mutex);
        return --_value;
    }

    //! return the current value -- should only be used for debugging.
    size_t value() const { return _value; }

private:
    //! value of the semaphore
    size_t _value;

    Mutex  _mutex;

    Cond  _cond;
private:
    Semaphore(const Semaphore&) ;
    Semaphore& operator = (const Semaphore&);
    
};

} 
#endif
